package fudan.se.project.service.infrastructure.entity.conference;


import fudan.se.project.controller.request.base.DateSet;
import fudan.se.project.domain.User;
import fudan.se.project.domain.conference.Conference;
import fudan.se.project.repository.entity.conference.ConferenceRepository;
import fudan.se.project.service.infrastructure.base.IEntityService;
import fudan.se.project.util.user.UserDetailsUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;

import static org.springframework.data.domain.PageRequest.of;

/**
 * @author Gao Longchao
 */
@Service
public class ConferenceService implements IEntityService<Conference> {


    private final ConferenceRepository conferenceRepository;
    private static final String DATE_START="dateStart";



    @Autowired
    public ConferenceService(ConferenceRepository conferenceRepository, UserDetailsUtil userDetailsUtil) {
        this.conferenceRepository = conferenceRepository;
    }

    public boolean isConferenceExistent(long id) {
        return null != this.findById(id);
    }

    public Conference changeConferenceState(Conference conference, Conference.ConferenceState state) {
        conference.setState(state);
        return this.save(conference);
    }

    public Conference changeConferenceStage(Conference conference, Conference.ConferenceStage stage) {
        conference.setStage(stage);
        return this.save(conference);
    }

    public Conference modifyConferenceDates(Conference conference, DateSet dateSet) {
        conference.setDeadline(dateSet.getDeadline());
        conference.setDateRelease(dateSet.getDateRelease());
        conference.setDateStart(dateSet.getDateStart());
        conference.setDateEnd(dateSet.getDateEnd());

        return this.save(conference);
    }


    //<editor-fold desc="entity query methods">

    @Override
    public Conference save(Conference conference) {
        return conferenceRepository.save(conference);
    }

    @Override
    public Iterable<Conference> saveAll(Collection<Conference> conferences) {
        return conferenceRepository.saveAll(conferences);
    }

    public Conference findById(long id) {
        return conferenceRepository.findById(id);
    }


    //<editor-fold desc="admin">
    public Page<Conference> findAllConferencesInPage(
            Conference.ConferenceState state,
            int page, int itemsPerPage
    ) {
        PageRequest pageRequest = of(page - 1, itemsPerPage,
                Sort.by(Sort.Direction.ASC, DATE_START));
        return conferenceRepository.
                findAllConferencesInPageByState(state, pageRequest);
    }

    public List<Conference> findAllConferences(Conference.ConferenceState state) {
        return conferenceRepository.
                findAllConferencesByState(state,
                        Sort.by(Sort.Direction.ASC, DATE_START)
                );
    }
    //</editor-fold>

    //<editor-fold desc="chair">
    public Page<Conference> findConferencesAsChairInPage(
            User user,
            Conference.ConferenceState state,
            int page, int itemsPerPage
    ) {
        PageRequest pageRequest = of(page - 1, itemsPerPage,
                Sort.by(Sort.Direction.ASC, DATE_START));
        return conferenceRepository.
                findConferencesAsChairInPageByState(user, state, pageRequest);
    }
    //</editor-fold>

    //<editor-fold desc="any">
    public Page<Conference> findConferencesAsAnyInPage(
            User user,
            Conference.ConferenceState state,
            Conference.ConferenceStage conferenceStage,
            int page, int itemsPerPage
    ) {

        PageRequest pageRequest = of(page - 1, itemsPerPage,
                Sort.by(Sort.Direction.ASC, DATE_START));
        return conferenceRepository.
                findConferencesAsAnyInPageByStateAndStage(user,
                        state, conferenceStage, pageRequest);
    }

    public Page<Conference> findConferencesAsAnyInPage(
            User user,
            Conference.ConferenceState state,
            int stageByDate,
            int page, int itemsPerPage
    ) {

        PageRequest pageRequest = of(page - 1, itemsPerPage,
                Sort.by(Sort.Direction.ASC, DATE_START));


        if (stageByDate == -1) {
            // ongoing
            return conferenceRepository.
                    findConferencesAsAnyInPageByStateAndNotStage(user,
                            state, Conference.ConferenceStage.CONFERENCE_END, pageRequest);
        } else {
            // completed
            return conferenceRepository.
                    findConferencesAsAnyInPageByStateAndStage(user,
                            state, Conference.ConferenceStage.CONFERENCE_END, pageRequest);
        }
    }
    //</editor-fold>

    //<editor-fold desc="all">
    public Page<Conference> findAllConferencesInPage(
            Conference.ConferenceState state,
            Conference.ConferenceStage stage,
            int page, int itemsPerPage
    ) {
        PageRequest pageRequest = of(page - 1, itemsPerPage,
                Sort.by(Sort.Direction.ASC, DATE_START));
        return conferenceRepository.
                findAllConferencesInPageByStateAndStage(state, stage, pageRequest);
    }

    public Page<Conference> findAllConferencesInPage(
            Conference.ConferenceState state,
            int stageByDate,
            int page, int itemsPerPage
    ) {

        PageRequest pageRequest = of(page - 1, itemsPerPage,
                Sort.by(Sort.Direction.ASC, DATE_START));


        if (stageByDate == -1) {
            // ongoing
            return conferenceRepository.
                    findAllConferencesInPageByStateAndNotStage(
                            state, Conference.ConferenceStage.CONFERENCE_END, pageRequest);
        } else {
            // completed
            return conferenceRepository.
                    findAllConferencesInPageByStateAndStage(
                            state, Conference.ConferenceStage.CONFERENCE_END, pageRequest);
        }
    }
    //</editor-fold>

    //</editor-fold>


}
